package Transaction;

import java.io.*;
import java.util.*; 

import Common.ByteArray;
import Common.GoggleDB;

import logmgr.CommitRecord;
import logmgr.LogMgr;


public class Recovery {
	public static RandomAccessFile file ;
	private static int activeTx = 0; 
	
	static {
		try { 
		if ( file == null ) {
			byte [] buff = new byte [ 4 ] ; 
			file = new RandomAccessFile ( "log.txt" , "rw") ;
			if ( file.length() == 0 ) {
				ByteArray.writeInt ( buff, 0, 4 ) ;
				file.write( buff ) ; 
			}
		}
		}catch ( Exception e) {
			e.printStackTrace() ;
			System.out.println ( "Failed error: log file can not be initialized") ; 
			System.exit( 0 ) ;
		}
	}
	
	public static synchronized void recoveryDB () throws Exception {
		HashSet < Integer> map = new HashSet < Integer > (); 
		byte buff [] = new byte [4 ] ;
		file.seek ( 0 ) ;
		file.read ( buff ) ; 
		int start = ByteArray.readInt ( buff, 0 ) ;
		file.seek ( start ) ;
		LogMgr rec = null ; 
		while ( ( rec = LogMgr.getNext() ) != null ) {
			rec.read () ;
			if ( rec instanceof CommitRecord ) map.add( rec.txnum ) ; 
		}
		
		file.seek ( start ) ;
		while ( ( rec = LogMgr.getNext() ) != null ) {
			rec.read () ;
			if ( map.contains( rec.txnum ) ) rec.redo () ;
			else rec.undo() ; 
		}
		setCheckPoint (); 
	}
		
	public static synchronized void start ( int txnum ) {
		LogMgr.allWrite( LogMgr.START , txnum, -1 , -1, null , null) ;
		activeTx ++ ; 
	}
	
	public static synchronized void commit ( int txnum ) {
		LogMgr.allWrite( LogMgr.COMMIT, txnum, -1 , -1,  null , null) ;
		activeTx -- ;
	//	System.out.println ( "set cheack point: " + txnum ) ; 
		setCheckPoint () ;
	}

	public static synchronized void rollback ( int txnum ) throws Exception {
		byte buff [] = new byte [4 ] ;
		file.seek ( 0 ) ;
		file.read ( buff ) ; 
		int start = ByteArray.readInt ( buff, 0 ) ;
		file.seek ( start ) ;
		LogMgr rec = null ; 		
		while ( ( rec = LogMgr.getNext() ) != null ) {
			rec.read () ;
			if (rec.txnum == txnum ) rec.undo() ; 
		}
		
		LogMgr.allWrite( LogMgr.ROLLBACK, txnum, -1, -1,  null, null) ;
		activeTx -- ;
		setCheckPoint(); 
	}
	
	public static synchronized void setCheckPoint () {
		if ( activeTx == 0 ) {
			try {
				//System.out.println ( "Set CheakPoint" )  ; 
				GoggleDB.bufferMgr.flushAll() ;
				LogMgr.allWrite( LogMgr.CHECKPOINT ,  -1,  -1, -1,  null, null ) ;
			}catch ( Exception e ) { 
				System.out.println ( "Write CHECKPOINT FAILED" ) ;
			}
		}
	}
	
	public static synchronized void setInt ( int txnum, int pageid, int pos, int old, int cur ) throws Exception {
		LogMgr.allWrite( LogMgr.INT , txnum, pageid, pos, old, cur) ;
	}
	
	public static synchronized void setString ( int txnum, int pageid, int pos, String old, String cur ) {
		LogMgr.allWrite( LogMgr.STRING , txnum, pageid, pos, old, cur) ;
	}

	public static synchronized void setShort ( int txnum, int pageid, int pos, Short old, Short cur ) {
		LogMgr.allWrite( LogMgr.SHORT , txnum, pageid, pos, old, cur) ;
	}
	
	public static synchronized void setChar ( int txnum, int pageid, int pos, Character old, Character cur ) {
		LogMgr.allWrite( LogMgr.CHAR , txnum, pageid, pos, old, cur) ;
	}
	
	public static synchronized void setFloat ( int txnum, int pageid, int pos, Float old, Float cur ) {
		LogMgr.allWrite( LogMgr.FLOAT , txnum, pageid, pos, old, cur) ;
	}
	
	public static synchronized void setBytes ( int txnum, int pageid, int pos, byte[] old, byte[] cur ) {
		LogMgr.allWrite( LogMgr.BYTES , txnum, pageid, pos, old, cur) ;
	}
	
}
